package com.general.framework.zzyy.blockQueue;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 *  * 阻塞队列的分类
 *  *
 *  * ArrayBlockingQueue: 由数组结构组成的有界阻塞队列.  【***】
 *  *
 *  * LinkedBlockingDeque: 由链表结构组成的有界(但大小默认值Integer>MAX_VALUE)阻塞队列.  【***】
 *  *
 *  * PriorityBlockingQueue:支持优先级排序的无界阻塞队列.
 *  *
 *  * DelayQueue: 使用优先级队列实现的延迟无界阻塞队列.
 *  *
 *  * SynchronousQueue:不存储元素的阻塞队列,也即是单个元素的队列.  【***】
 *  *
 *  * LinkedTransferQueue:由链表结构组成的无界阻塞队列.
 *  *
 *  * LinkedBlockingDeque:由了解结构组成的双向阻塞队列.
 *  *
 *  *
 *  Description * 一个初始值为0的变量 两个线程交替操作 一个加1 一个减1来5轮
 *
 **/
public class ProductConsumerTraditionDemo {
    public static void main(String[] args) {
        ShareData shareData = new ShareData();
        new Thread(() -> {
            for (int i = 1; i <= 5; i++) {
                try {
                    shareData.increment();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "AA").start();
        new Thread(() -> {
            for (int i = 1; i <= 5; i++) {
                try {
                    shareData.deIncrement();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "BB").start();
    }
}

/**
 * 共享资源类
 */
class ShareData {
    private int num = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void increment() throws Exception {
        lock.lock();
        try {
            // 1. 判断 多线程判断时，一定要用while ******
            while (num != 0) {
                // 等待，不能生产
                condition.await();
            }
            // 2. 干活
            num++;
            System.out.println(Thread.currentThread().getName() + "\t" + num);
            // 3. 通知唤醒
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void deIncrement() throws Exception {
        lock.lock();
        try {
            // 判断 多线程判断时，一定要用while ******
            while (num == 0) {
                // 等待，不能生产
                condition.await();
            }
            // 干活
            num--;
            System.out.println(Thread.currentThread().getName() + "\t" + num);
            // 通知唤醒
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}